Кэширование страниц
===================

Кэширование страниц — это кэширование всего содержимого страницы. Кэширование
страниц может встречаться в различных местах. Например, выбрав соответствующий
странице заголовок, браузер пользователя может кэшировать просматриваемую
страницу на некоторое время. Веб-приложение также может само хранить содержимое
страницы в кэше.

Кэширование вывода
------------------

Кэширование страницы может быть рассмотрено как частный случай [кэширования
фрагмента](/doc/guide/caching.fragment). Из-за того что содержимое страницы
часто генерируется применением макета к представлению, кэширование не будет
работать, если мы просто вызовем в макете методы
[beginCache()|CBaseController::beginCache] и
[endCache()|CBaseController::endCache]. Причина этого в том, что
макет применяется при вызове метода [CController::render()] *после*
формирования содержимого представления.

Для кэширования всей страницы мы должны пропустить этап формирования
содержимого страницы. Для выполнения этой задачи мы можем использовать класс
[COutputCache] как  [фильтр](/doc/guide/basics.controller#filter) действия.
В коде ниже показано, как можно сконфигурировать фильтр кэша:

~~~
[php]
public function filters()
{
	return array(
		array(
			'COutputCache',
			'duration'=>100,
			'varyByParam'=>array('id'),
		),
	);
}
~~~

Вышеприведённая конфигурация создаёт фильтр, применяемый ко всем
действиям контроллера. Мы можем ограничить его применение одним или
несколькими действиями, используя оператор `+`.
Подробнее с работой фильтров можно ознакомиться в теме
[фильтры](/doc/guide/basics.controller#filter).

> Tip|Подсказка: Мы можем использовать класс [COutputCache] в качестве фильтра,
поскольку он наследует класс [CFilterWidget], т.е. оба этих класса одновременно
являются и виджетами, и фильтрами. Фактически, способ работы виджета очень похож
на работу фильтра: виджет (фильтр) выполняется до того, как любое вложенное
содержимое (действие) будет сформировано (выполнено), а выполнение виджета
(фильтра) заканчивается после того, как вложенное содержимое (действие)
будет сформировано (выполнено).

HTTP-кэширование
----------------

В дополнение к кешированию всего вывода действия контроллера в Yii с версии
1.1.11 есть [CHttpCacheFilter]. Данный фильтр отсылает рассматриваемые далее
HTTP-заголовки, которые говорят клиенту (чаще всего браузеру), что содержимое
страницы не менялось с последнего запроса. В этом случае серверу нет необходимости
повторно формировать и отсылать страницу. [CHttpCacheFilter] настраивается
также, как и [COutputCache]:

~~~
[php]
public function filters()
{
    return array(
        array(
            'CHttpCacheFilter + index',
            'lastModified'=>Yii::app()->db->createCommand("SELECT MAX(`update_time`) FROM {{post}}")->queryScalar(),
        ),
    );
}
~~~

Приведённый выше код добавит заголовок `Last-Modified` с значением, равным
последней дате изменения записи. Также вы можете  использовать
[CHttpCacheFilter::lastModifiedExpression] для того, чтобы задать значение
`Last-Modified` при помощи выражения PHP.

> Tip|Подсказка: Как [CHttpCacheFilter::lastModifiedExpression], так и
[CHttpCacheFilter::lastModified] могут принимать как Unix timestamp в виде
целого числа, так и дату строкой в понятном человеку формате. Если дату может
разобрать [strtotime()](http://php.net/manual/ru/function.strtotime.php), то
никаких дополнительных преобразований не требуется.

Похожим образом, через [CHttpCacheFilter::etagSeed] и
[CHttpCacheFilter::etagSeedExpression], может быть добавлен заголовок
«Entity Tag» (`ETag`). Заданные значения сериализуются (то есть можно использовать
как простое значение, так и массив) и затем используются для генерации хеша
quoted base64 SHA1, который подставляется в `ETag`. Данный способ отличается от
того, что используется [Apache](http://httpd.apache.org) и другими веб-серверами.
Тем не менее, реализация в Yii полностью соответствует RFC и лучше подходит
для использования в фреймворке.

> Note|Примечание: Для соответствия [разделу 13.3.4 RFC 2616](http://tools.ietf.org/html/rfc2616#section-13.3.4),
[CHttpCacheFilter] отсылает как `ETag` *так и* `Last-Modified` когда это возможно.
Соответственно, оба заголовка будут использоваться для инвалидации кэша.

Так как `ETag` является хешем, то позволяет реализовать более сложные и точные
стратегии кеширования, чем в случае использования `Last-Modified`. К примеру, ETag
может быть инвалидирован в случае изменения темы сайта.

> Tip|Подсказка: Использование «дорогих» в плане производительности выражений
в [CHttpCacheFilter::etagSeedExpression] может свести на нет ожидаемую выгоду
от использования [CHttpCacheFilter] и даже привести к замедлению приложения потому
как используемое выражение выполняется при каждом запросе. Всегда старайтесь найти
наиболее простое выражение, показывающее факт изменения содержимого страницы.

### Влияние на SEO

Поисковые роботы обычно обращают внимание на заголовки, относящиеся к кэшированию.
Так как у некоторых из них есть ограничения на обработку определённого количества
страниц одного домена в единицу времени, то использование данной техники может
помочь индексации сайта.